package com.zndroid.base.adapter;

import android.view.View;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;

import com.chad.library.adapter.base.BaseBinderAdapter;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.binder.BaseItemBinder;
import com.chad.library.adapter.base.module.BaseDraggableModule;
import com.chad.library.adapter.base.module.BaseLoadMoreModule;
import com.chad.library.adapter.base.module.BaseUpFetchModule;
import com.chad.library.adapter.base.module.DraggableModule;
import com.chad.library.adapter.base.module.LoadMoreModule;
import com.chad.library.adapter.base.module.UpFetchModule;
import com.chad.library.adapter.base.viewholder.BaseViewHolder;
import com.zndroid.base.annotation.IAdapterType;
import com.zndroid.base.binder.AbsBinder;
import com.zndroid.base.callback.IOnItemChildClickListener;
import com.zndroid.base.callback.IOnItemChildLongClickListener;
import com.zndroid.base.callback.IOnItemClickListener;
import com.zndroid.base.callback.IOnItemLongClickListener;
import com.zndroid.base.exception.SupplyIllegalArgumentException;

import java.util.Collection;
import java.util.List;
import java.util.Observer;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * base adapter for common list
 *
 * @author lazy
 * @date 3/25/21
 */
@SuppressWarnings("unused")
public abstract class BaseAdapter<T> extends BaseBinderAdapter implements
        LoadMoreModule,
        UpFetchModule,
        DraggableModule
{
    private IOnItemClickListener<T> itemClickListener;
    private IOnItemLongClickListener<T> itemLongClickListener;
    private IOnItemChildClickListener<T> itemChildClickListener;
    private IOnItemChildLongClickListener<T> itemChildLongClickListener;

    /**观察数据选择变化*/
    private DataChangeObservable<T> changeObservable;
    /**增删快*/
    private List<T> selectedList = new CopyOnWriteArrayList<T>();

    private @IAdapterType
    int adapterType = IAdapterType.DEF;

    /**
     * changed statue when selected current item
     * @param viewHolder BaseViewHolder
     * */
    protected abstract void onBackItemSelected(@NonNull BaseViewHolder viewHolder);
    /**
     * changed statue when unselected current item
     * @param viewHolder BaseViewHolder
     * */
    protected abstract void onBackItemUnSelected(@NonNull BaseViewHolder viewHolder);

    /**
     * tell me your Entity type
     *
     * @return class for T
     * */
    protected abstract Class<T> onSupplyEntityClazz();

    /**
     * supply adapter type for default show. default {@link IAdapterType#DEF}
     *
     * support {@link IAdapterType#DEF} or {@link IAdapterType#SINGLE} or {@link IAdapterType#MULTI}
     * and then you can call {@link #toSwitchType(int)} to change it.
     *
     * */
    public BaseAdapter() {
        plugInListener();
        plugInDataChangeObserver();
    }

    /**
     * supply adapter type for default show. default {@link IAdapterType#DEF}
     *
     * support {@link IAdapterType#DEF} or {@link IAdapterType#SINGLE} or {@link IAdapterType#MULTI}
     * and then you can call {@link #toSwitchType(int)} to change it.
     *
     * @param adapterType  int adapter type
     * */
    public BaseAdapter(@IAdapterType int adapterType) {
        this.adapterType = adapterType;

        plugInListener();
        plugInDataChangeObserver();
    }

    /**
     * supply adapter type to show. default {@link IAdapterType#DEF}
     *
     * support {@link IAdapterType#DEF} or {@link IAdapterType#SINGLE} or {@link IAdapterType#MULTI}
     * and then you can call {@link #toSwitchType(int)} to change it.
     *
     * @param adapterType  int adapter type
     * */
    public BaseAdapter(@IAdapterType int adapterType, @Nullable List<Object> list) {
        super(list);
        this.adapterType = adapterType;

        plugInListener();
        plugInDataChangeObserver();
    }

    private void plugInListener() {
        // 内部重新实现点击和长按事件
        setOnItemClickListener(null);
        setOnItemLongClickListener(null);
        setOnItemChildClickListener(null);
        setOnItemChildLongClickListener(null);
    }

    private void plugInDataChangeObserver() {
        if (null == changeObservable) {
            changeObservable = new DataChangeObservable<>();
        }
    }

    public void toBindItem(BaseItemBinder<T, ? extends BaseViewHolder> itemBinder) {
        addItemBinder(onSupplyEntityClazz(), itemBinder, null);
    }

    public void toBindDataChange(@NonNull Observer observer) {
        changeObservable.addObserver(observer);
    }

    /**
     * get current adapter type
     *
     * @return adapter type
     * */
    public int getAdapterType() {
        return adapterType;
    }

    /**
     * switch adapter type, and will clear have been selected list.
     *
     * @param adapterType int of {@link IAdapterType} type
     * */
    public void toSwitchType(@IAdapterType int adapterType) {
        this.adapterType = adapterType;
        selectedList.clear();
        notifyDataSetChanged();
    }

    public void setItemClickListener(IOnItemClickListener<T> itemClickListener) {
        this.itemClickListener = itemClickListener;
    }

    public void setItemLongClickListener(IOnItemLongClickListener<T> itemLongClickListener) {
        this.itemLongClickListener = itemLongClickListener;
    }

    public void setItemChildClickListener(IOnItemChildClickListener<T> itemChildClickListener) {
        this.itemChildClickListener = itemChildClickListener;
    }

    public void setItemChildLongClickListener(IOnItemChildLongClickListener<T> itemChildLongClickListener) {
        this.itemChildLongClickListener = itemChildLongClickListener;
    }

    @NonNull
    @Override
    public BaseLoadMoreModule addLoadMoreModule(@NonNull BaseQuickAdapter<?, ?> baseQuickAdapter) {
        return new BaseLoadMoreModule(baseQuickAdapter);
    }

    @NonNull
    @Override
    public BaseDraggableModule addDraggableModule(@NonNull BaseQuickAdapter<?, ?> baseQuickAdapter) {
        return new BaseDraggableModule(baseQuickAdapter);
    }

    @NonNull
    @Override
    public BaseUpFetchModule addUpFetchModule(@NonNull BaseQuickAdapter<?, ?> baseQuickAdapter) {
        return new BaseUpFetchModule(baseQuickAdapter);
    }

    /**
     * 注意这里会重置 load more 状态
     * */
    @Override
    public void setList(@Nullable Collection<?> list) {
        super.setList(list);
    }

    /**
     * @deprecated instead of {@link #setList(Collection)}
     * */
    @Override
    public void setNewInstance(@Nullable List<Object> list) {
        super.setNewInstance(list);
    }

    @Override
    protected void convert(@NonNull BaseViewHolder viewHolder, @NonNull Object item) {
        super.convert(viewHolder, item);
        if (selectedList.contains(item)) {
            if (IAdapterType.SINGLE == adapterType) {
                lastPosition = getItemPosition(item);
            }
            onBackItemSelected(viewHolder);
        } else {
            onBackItemUnSelected(viewHolder);
        }
    }

    @Override
    protected void convert(@NonNull BaseViewHolder viewHolder, @NonNull Object item, @NonNull List<?> payloads) {
        super.convert(viewHolder, item, payloads);
        if (selectedList.contains(item)) {
            if (IAdapterType.SINGLE == adapterType) {
                lastPosition = getItemPosition(item);
            }
            onBackItemSelected(viewHolder);
        } else {
            onBackItemUnSelected(viewHolder);
        }
    }

    @Override
    protected void bindClick(@NonNull BaseViewHolder viewHolder) {
        // new impl
        bindItemClick(viewHolder);
        bindItemLongClick(viewHolder);
    }

    @Override
    protected void bindChildClick(@NonNull BaseViewHolder viewHolder, int viewType) {
        // new impl
        bindChildOfItemClick(viewHolder, viewType);
        bindChildOfItemLongClick(viewHolder, viewType);
    }

    private void bindChildOfItemClick(@NonNull BaseViewHolder viewHolder, int viewType) {
        BaseItemBinder<Object, BaseViewHolder> binder = getItemBinder(viewType);

        for (int id : binder.getChildClickViewIds()) {
            View childView = viewHolder.itemView.findViewById(id);
            if (!childView.isClickable()) {
                childView.setClickable(true);
            }

            if (binder instanceof AbsBinder) {
                if (id == ((AbsBinder<Object>) binder).getSupportSelectViewId()) {
                    /*设置了 子控件 控制选中效果*/
                    bindChildClicked(childView, viewHolder, binder, true);
                } else {
                    /*其他情况照旧*/
                    bindChildClicked(childView, viewHolder, binder, false);
                }
            } else {
                /*其他情况照旧*/
                bindChildClicked(childView, viewHolder, binder, false);
            }
        }

    }

    private void bindChildClicked(@NonNull View childView, @NonNull BaseViewHolder viewHolder, @NonNull BaseItemBinder<Object, BaseViewHolder> binder, boolean isSupportSelected) {
        childView.setOnClickListener(view -> {
            int position = viewHolder.getBindingAdapterPosition();
            if (position == RecyclerView.NO_POSITION) {
                return;
            }

            position -= getHeaderLayoutCount();

            if (isNotEmpty(getData())) {
                Object item = getData().get(position);

                if (isSupportSelected) {
                    updateSelect(viewHolder, (T) item);
                }

                // dispatch binder
                binder.onChildClick(viewHolder, view, item, position);

                // dispatch listener
                dispatchOnItemChildClick(view, position, (T) item);

                // notify data change
                dispatchDataChange();
            }
        });
    }

    private void bindChildOfItemLongClick(@NonNull BaseViewHolder viewHolder, int viewType) {
        BaseItemBinder<Object, BaseViewHolder> binder = getItemBinder(viewType);

        for (int id : binder.getChildClickViewIds()) {
            View childView = viewHolder.itemView.findViewById(id);
            if (!childView.isLongClickable()) {
                childView.setLongClickable(true);
            }

            childView.setOnLongClickListener(view -> {
                int position = viewHolder.getBindingAdapterPosition();
                if (position == RecyclerView.NO_POSITION) {
                    return false;
                }

                position -= getHeaderLayoutCount();

                if (isNotEmpty(getData())) {
                    Object item = getData().get(position);

                    // dispatch listener
                    if (!dispatchOnItemChildLongClick(view, position, (T) item)) {/*如果未处理回调则继续检查binder中是否处理了回调，保证长按事件只会走其中之一*/
                        // dispatch binder
                        return binder.onChildLongClick(viewHolder, view, item, position);
                    }
                }

                return false;
            });
        }

    }

    private void bindItemClick(@NonNull BaseViewHolder viewHolder) {
        viewHolder.itemView.setOnClickListener(v -> {
            int position = viewHolder.getBindingAdapterPosition();
            if (position == RecyclerView.NO_POSITION) {
                return;
            }
            position -= getHeaderLayoutCount();

            if (isNotEmpty(getData())) {
                Object item = getData().get(position);

                int itemViewType = viewHolder.getItemViewType();

                // update statue
                BaseItemBinder<Object, BaseViewHolder> binder = getItemBinder(itemViewType);
                if (binder instanceof AbsBinder) {
                    /*没有指定【选择】功能的控件id*/
                    if (-1 == ((AbsBinder<Object>) binder).getSupportSelectViewId()) {
                        updateSelect(viewHolder, (T) item);
                    }
                } else {
                    updateSelect(viewHolder, (T) item);
                }

                // dispatch binder
                dispatchBinderClick(viewHolder, v, item, position);

                // dispatch listener
                dispatchOnItemClick(v, position, (T) item);

                // notify data change
                dispatchDataChange();
            }

        });
    }

    private void bindItemLongClick(@NonNull BaseViewHolder viewHolder) {
        viewHolder.itemView.setOnLongClickListener(v -> {
            int position = viewHolder.getBindingAdapterPosition();
            if (position == RecyclerView.NO_POSITION) {
                return false;
            }
            position -= getHeaderLayoutCount();

            int itemViewType = viewHolder.getItemViewType();
            BaseItemBinder<Object, BaseViewHolder> binder = getItemBinder(itemViewType);

            if (isNotEmpty(getData())) {
                Object item = getData().get(position);

                // dispatch listener
                if (!dispatchOnItemLongClick(v, position, (T) item)) {/*如果未处理回调则继续检查binder中是否处理了回调，保证长按事件只会走其中之一*/
                    // dispatch binder
                    return binder.onLongClick(viewHolder, v, item, position);
                }
            }

            return false;
        });
    }

    /**
     * 点击事件分发到Binder {@link #toBindItem(BaseItemBinder)}
     * */
    private void dispatchBinderClick(@NonNull BaseViewHolder viewHolder, @NonNull View v, Object item, int position) {
        int itemViewType = viewHolder.getItemViewType();
        BaseItemBinder<Object, BaseViewHolder> binder = getItemBinder(itemViewType);
        binder.onClick(viewHolder, v, item, position);
    }

    private void dispatchDataChange() {
        if (null != changeObservable) {
            changeObservable.dataChanged(getSelectedList());
        }
    }

    private void dispatchOnItemClick(@NonNull View view, int position, @Nullable T t) {
        if (null != itemClickListener) {
            itemClickListener.onBackItemClicked(view, position, t);
        }
    }

    private boolean dispatchOnItemLongClick(@NonNull View view, int position, @Nullable T t) {
        if (null != itemClickListener) {
            return itemLongClickListener.onBackItemLongClicked(view, position, t);
        }

        return false;
    }

    private void dispatchOnItemChildClick(@NonNull View view, int position, @Nullable T t) {
        if (null != itemChildClickListener) {
            itemChildClickListener.onBackItemChildClicked(view, position, t);
        }
    }

    private boolean dispatchOnItemChildLongClick(@NonNull View view, int position, @Nullable T t) {
        if (null != itemChildLongClickListener) {
            return itemChildLongClickListener.onBackItemChildLongClicked(view, position, t);
        }

        return false;
    }

    private int lastPosition = -1;
    private void updateSelect(BaseViewHolder viewHolder, T t) {
        if (IAdapterType.MULTI == adapterType) {
            if (selectedList.contains(t)) {
                selectedList.remove(t);
                onBackItemUnSelected(viewHolder);
            } else {
                selectedList.add(t);
                onBackItemSelected(viewHolder);
            }
        } else if (IAdapterType.SINGLE == adapterType) {
            int position = viewHolder.getBindingAdapterPosition();

            if (lastPosition == position
                    && selectedList.contains(t)) {
                BaseViewHolder vh = (BaseViewHolder) getRecyclerView().findViewHolderForLayoutPosition(position);
                onBackItemUnSelected(vh);

                selectedList.clear();
            } else {
                if (lastPosition != -1) {
                    BaseViewHolder vh = (BaseViewHolder) getRecyclerView().findViewHolderForLayoutPosition(lastPosition);
                    /** 上次选择的 vh 还在可视的界面中 */if (null != vh) {
                        onBackItemUnSelected(vh);
                    /** 上次选择的 vh 已经被回收 */} else {
                        notifyItemChanged(lastPosition);
                    }
                }
                onBackItemSelected(viewHolder);

                selectedList.clear();
                selectedList.add(t);
            }

            lastPosition = position;
        }
    }

    /**
     * select all, valid when {@link IAdapterType#MULTI}
     * */
    public void toSelectAll() {
        if (IAdapterType.MULTI == adapterType) {
            //bug fixed by lazy at 2021/04/21
            //selectedList = (List<T>) getData(); 如果是基本类型数据，比如：String，
            //是直接引用的同一内存地址，所以，getData()的行为会绑定到selectedList，从而导致
            //调用toUnSelectAll方法时，会清空getData();
            selectedList.clear();
            selectedList.addAll((Collection<? extends T>) getData());
            dispatchDataChange();
            notifyDataSetChanged();
        }
    }

    /**
     * un select all
     * */
    public void toUnSelectAll() {
        selectedList.clear();
        dispatchDataChange();
        notifyDataSetChanged();
    }

    /**
     * has selected
     * @param expectList expectList
     * */
    public void toSelect(List<T> expectList) {
        if (IAdapterType.MULTI == adapterType) {
            selectedList = expectList;
            notifyDataSetChanged();
        } else if (IAdapterType.SINGLE == adapterType){
            if (null != expectList && expectList.size() > 1) {
                throw new SupplyIllegalArgumentException("expectList", "only select one item when single adapter.");
            }
            selectedList = expectList;
            notifyDataSetChanged();
        }
    }

    /**
     * get select list
     *
     * @return List selectList
     * */
    public List<T> getSelectedList() {
        return selectedList;
    }

    /**
     * check 'collection' is empty or not
     *
     * @param collection your collection
     * @return true or false
     * */
    public boolean isNotEmpty(Collection<?> collection) {
        return null != collection && !collection.isEmpty();
    }
}
